package com.xyauto.theme.view.seekbar;

import android.content.Context;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.Point;
import android.graphics.RectF;
import android.graphics.drawable.BitmapDrawable;
import android.media.ThumbnailUtils;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;

import com.xyauto.theme.view.seekbar.interfaces.ISeekBar;

import java.lang.ref.SoftReference;
import java.util.HashMap;

public class ReverseSeekArc extends BaseSeekBar implements ISeekBar {

    private static final String TAG = ReverseSeekArc.class.getSimpleName();
    private static int INVALID_PROGRESS_VALUE = -1;
    private final int angleOffset = -90;
    private int breachHight = 0;
    private int startAngle_ = 0;
    private int rotation = 0;
    private boolean mRoundedEdges = false;
    private boolean touchInside = true;
    // Internal variables
    private int arcRadius = 0;

    private float mProgressSweep = 0;
    private RectF arcRect = new RectF();
    private Paint arcPaint;
    private Paint mProgressPaint;
    private int mTranslateCenterX;
    private int mTranslateCenterY;
    private int mThumbXPos;
    private int mThumbYPos;
    private double mTouchAngle;
    private float mTouchIgnoreRadius;
    private OnSeekArcChangeListener mOnSeekArcChangeListener;
    private int fu = -1;
    private int layoutHeight;
    private int layoutWidth;
    private Bitmap highLigtbitmap;
    private boolean Destroy;
    private int direction;
    private boolean isBroadsideArc;
    private int hightLightWidth;
    private int hightLightHeight;
    private static final int DIRECTION_TOP = 2;
    private static final int DIRECTION_BOTTOM = 3;
    private static final int DIRECTION_LEFT = 4;
    private static final int DIRECTION_RIGHT = 5;

    @Override
    public void setSeekBarMax(int totalTime) {
        setMax(totalTime);
    }

    @Override
    public void setSeekBarProgress(int totalTime) {
        setProgress(totalTime);
    }

    public interface OnSeekArcChangeListener {

        /**
         * @param seekArc  The SeekArc whose mProgress has changed
         * @param progress The current mProgress level. This will be in the range
         *                 0..mMax where mMax was set by
         * @param fromUser True if the mProgress change was initiated by the user.
         */
        void onProgressChanged(ReverseSeekArc seekArc, int progress, boolean fromUser);

        /**
         * @param seekArc The SeekArc in which the touch gesture began
         */
        void onStartTrackingTouch(ReverseSeekArc seekArc);

        /**
         * @param seekArc The SeekArc in which the touch gesture began
         */
        void onStopTrackingTouch(ReverseSeekArc seekArc);
    }

    public ReverseSeekArc(Context context) {
        super(context);
        init(context, null, 0);
    }

    public ReverseSeekArc(Context context, AttributeSet attrs) {
        super(context, attrs);
        init(context, attrs, 0);
    }

    public ReverseSeekArc(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        init(context, attrs, defStyle);
    }

    @Override
    protected void refreshDrawable() {

    }

    private void init(Context context, AttributeSet attrs, int defStyle) {
        cache = new HashMap<Integer, SoftReference<Bitmap>>();
        final Resources res = getResources();
        float density = context.getResources().getDisplayMetrics().density;

        int arcColor = res.getColor(android.R.color.background_dark);
        int progressColor = res.getColor(android.R.color.holo_blue_light);
        int thumbHalfheight = 0;
        int thumbHalfWidth = 0;
        breachHight = 0;
        // Convert mProgress width to pixels for current density
        setProgressWidth((int) (getProgressWidth() * density));

        if (attrs != null) {
            // init
            init(context, attrs, defStyle, 0);


            if (getThumb() != null) {
                thumbHalfheight = (int) getThumb().getIntrinsicHeight() / 2;
                thumbHalfWidth = (int) getThumb().getIntrinsicWidth() / 2;
                Log.e(TAG + 1, "mThumb.getIntrinsicHeight():" + getThumb().getIntrinsicHeight()
                        + "mThumb.getIntrinsicWidth():" + getThumb().getIntrinsicWidth()
                        + getResources().getDisplayMetrics().density);
                getThumb().setBounds(-thumbHalfWidth, -thumbHalfheight, thumbHalfWidth, thumbHalfheight);
            }

            if (getHighLightDrawable() != null) {
                try {
                    highLigtbitmap = ((BitmapDrawable) getHighLightDrawable()).getBitmap();
                    hightLightWidth = highLigtbitmap.getWidth();
                    hightLightHeight = highLigtbitmap.getHeight();
                    Log.e(TAG + 1, "mThumb.getIntrinsicWidth():" + highLigtbitmap.getWidth()
                            + "mThumb.getIntrinsicHeight():" + highLigtbitmap.getHeight()
                            + getResources().getDisplayMetrics().density);
                    int hingLightDrawableHalfHeight = getHighLightDrawable().getIntrinsicHeight() / 2;
                    int hingLightDrawableHalfWidth = getHighLightDrawable().getIntrinsicWidth() / 2;
                    getHighLightDrawable().setBounds(-hingLightDrawableHalfWidth, -hingLightDrawableHalfHeight,
                            hingLightDrawableHalfWidth, hingLightDrawableHalfHeight);

                } catch (Exception e) {
                    // TODO: handle exception
                }

            }

            if (direction == 2 || direction == 3 || direction == 4 || direction == 5) {
                isBroadsideArc = true;
            }

            // mMax
            // arc
            if (getMaxSweepAngle() < getStartAngle()) {
                rotation = getStartAngle();
                startAngle_ = getStartAngle();
                setStartAngle(0);
                setMaxSweepAngle(startAngle_ - getMaxSweepAngle());
            } else if (getMaxSweepAngle() > getStartAngle()) {
                rotation = 0;

                setMaxSweepAngle(getMaxSweepAngle() - getStartAngle());
            } else {
                rotation = 0;
                setStartAngle(0);
                setMaxSweepAngle(0);
            }
        }
        setProgressWidth((getProgress() > getMax()) ? getMax() : getProgress());
        setProgressWidth((getProgress() < 0) ? 0 : getProgress());

        setMaxSweepAngle((getMaxSweepAngle() > 360) ? 360 : getMaxSweepAngle());
        setMaxSweepAngle((getMaxSweepAngle() < 0) ? 0 : getMaxSweepAngle());

        setStartAngle((getStartAngle() > 360) ? 0 : getStartAngle());
        setStartAngle((getStartAngle() < 0) ? 0 : getStartAngle());

        arcPaint = new Paint();
        arcPaint.setColor(arcColor);
        arcPaint.setAntiAlias(true);
        arcPaint.setStyle(Paint.Style.STROKE);
        arcPaint.setStrokeWidth(getArcWidth());

        mProgressPaint = new Paint();
        mProgressPaint.setColor(progressColor);
        mProgressPaint.setAntiAlias(true);
        mProgressPaint.setStyle(Paint.Style.STROKE);
        mProgressPaint.setStrokeWidth(getProgressWidth());

        if (mRoundedEdges) {
            arcPaint.setStrokeCap(Paint.Cap.ROUND);
            mProgressPaint.setStrokeCap(Paint.Cap.ROUND);
        }
    }

    private int getStartAn1gle_0(int breachHight, int radios) {
        if (radios < min_layout && direction == DIRECTION_TOP) {
            float b = radios - breachHight;
            float alpha = b / radios;
            double f = arccos(alpha);
            int angle = (int) Math.round(f);
            return 360 - angle * 2;

        } else if (radios >= min_layout && direction == DIRECTION_TOP) {
            if (radios == min_layout) {
                return 180;
            }
            float b = radios - breachHight;
            float alpha = b / radios;
            double f = arccos(alpha);
            int angle = (int) Math.round(f);
            return (180 - angle) * 2;
        }
        if (radios < min_layout && direction == DIRECTION_LEFT) {
            float b = radios - breachHight;
            float alpha = b / radios;
            double f = arccos(alpha);
            int angle = (int) Math.round(f);

            return 360 - angle * 2;
        } else if (radios >= min_layout && direction == DIRECTION_LEFT) {
            if (radios == min_layout) {
                return 180;
            }
            float b = radios - breachHight;
            float alpha = b / radios;
            double f = arccos(alpha);
            int x = (int) Math.round(f) / 2;

            return (180 - x);
        }

        if (radios < min_layout && direction == DIRECTION_RIGHT) {
            float b = radios - breachHight;
            float alpha = b / radios;
            double f = arccos(alpha);
            int angle = (int) Math.round(f);

            return 360 - angle * 2;
        } else if (radios >= min_layout && direction == DIRECTION_RIGHT) {
            if (radios == min_layout) {
                return 180;
            }
            float b = radios - breachHight;
            float alpha = b / radios;
            double f = arccos(alpha);
            int x = (int) Math.round(f) / 2;

            return (180 - x);
        }
        if (radios < min_layout && direction == DIRECTION_BOTTOM) {
            float b = radios - breachHight;
            float alpha = b / radios;
            double f = arccos(alpha);
            int angle = (int) Math.round(f);

            return 360 - angle * 2;
        } else if (radios >= min_layout && direction == DIRECTION_BOTTOM) {
            if (radios == min_layout) {
                return 180;
            }
            float b = radios - breachHight;
            float alpha = b / radios;
            double f = arccos(alpha);
            int x = (int) Math.round(f) / 2;

            return (180 - x);
        }
        return 0;
    }

    int count = 0;
    Point point0 = new Point();

    HashMap<Integer, SoftReference<Bitmap>> cache;
    private int min_layout;
    private int max_layout;
    private String text = "This is text";


    @Override
    protected void onDraw(Canvas canvas) {
        System.out.println(TAG + ":onDraw");
        canvas.scale(-1, 1, arcRect.centerX(), arcRect.centerY());
        // Draw the arcs
        final int arcStart = getStartAngle() + angleOffset + rotation;

        if (getBackground() != null) {
            getBackground().draw(canvas);
        }

        canvas.drawText(text, 150, -10, arcPaint);
        /**
         * mProgress mBackground , way of clip and path
         */

        if (highLigtbitmap != null) {

            if (mProgressSweep > 3) {
                canvas.save();
                highLigtbitmap = ThumbnailUtils.extractThumbnail(highLigtbitmap, (int) arcRect.width(),
                        (int) arcRect.height());
                Path path = new Path();
                path.moveTo(mTranslateCenterX, mTranslateCenterY);
                path.arcTo(arcRect, arcStart, mProgressSweep);
                path.lineTo(mTranslateCenterX, mTranslateCenterY);
                canvas.clipPath(path);
                // mHighLightDrawable.draw(canvas);
                canvas.drawBitmap(highLigtbitmap, arcRect.left, arcRect.top, mProgressPaint);
                canvas.restore();
            }
        }

        /**
         * rotate of it`s self center
         *
         */
        if (getThumb() != null) {

            if (getThumb().getIntrinsicHeight() > arcRadius) {
                canvas.rotate((int) mProgressSweep, arcRect.centerX(), arcRect.centerY());
                getThumb().draw(canvas);
            }

        }
    }

    void recycleAllnotUsedBitmap() {
        if (cache != null) {
            if (Destroy) {
                for (SoftReference<Bitmap> iterable_element : cache.values()) {
                    if (iterable_element != null) {
                        if (iterable_element.get() != null && !iterable_element.get().isRecycled()) {
                            Bitmap b = iterable_element.get();
                            b.recycle();
                            b = null;
                        }
                    }
                }
            }

        }
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        System.out.println(TAG + ":onMeasure");
        layoutHeight = getDefaultSize(getSuggestedMinimumHeight(), heightMeasureSpec);
        layoutWidth = getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec);

        min_layout = Math.min(layoutWidth, layoutHeight);
        max_layout = Math.max(layoutWidth, layoutHeight);

        float top = 0;
        float left = 0;
        int arcDiameter = 0;

        mTranslateCenterX = (int) (max_layout * 0.5f);
        mTranslateCenterY = (int) (max_layout * 0.5f);

        arcDiameter = max_layout - getPaddingBottom() * 2;
        arcRadius = arcDiameter / 2;

        breachHight = Math.abs(max_layout - min_layout);
        breachHight = 0;

        if (arcRadius != 0 && fu < 4 && breachHight != 0) {
            setMaxSweepAngle(getStartAn1gle_0(breachHight, arcRadius));
            Log.e("0115", "" + getMaxSweepAngle());
            if (direction == DIRECTION_TOP) {
                if (arcRadius >= min_layout) {
                    rotation = 360 - getMaxSweepAngle() / 2;
                } else
                    rotation = 360 - getMaxSweepAngle() / 2;
            } else if (direction == DIRECTION_LEFT) {
                rotation = 270 - getMaxSweepAngle() / 2;
            } else if (direction == DIRECTION_RIGHT) {
                if (arcRadius > min_layout) {
                    rotation = 90 - getMaxSweepAngle() / 2;

                } else if (arcRadius == min_layout) {
                    rotation = 0;
                } else

                    rotation = 270;
                rotation = 270 - getMaxSweepAngle() / 2;
            } else if (direction == DIRECTION_BOTTOM) {
                if (arcRadius >= min_layout) {
                    rotation = 180 - getMaxSweepAngle() / 2;
                }
            }
            fu++;
        }

        top = (layoutWidth > layoutHeight ? layoutWidth : layoutHeight) / 2 - (arcDiameter / 2);
        left = (layoutWidth > layoutHeight ? layoutWidth : layoutHeight) / 2 - (arcDiameter / 2);

        arcRect.set(left, top, left + arcDiameter, top + arcDiameter);

        if (getBackground() != null) {
            getBackground().setBounds((int) arcRect.left, (int) arcRect.top, (int) arcRect.right, (int) arcRect.bottom);
        }

        if (getThumb() != null) {
            getThumb().setBounds((int) arcRect.left, (int) arcRect.top, (int) arcRect.right, (int) arcRect.bottom);
        }

        int arcStart = (int) mProgressSweep + getStartAngle() + rotation + 90;
        mThumbXPos = (int) (arcRadius * Math.cos(Math.toRadians(arcStart)));
        mThumbYPos = (int) (arcRadius * Math.sin(Math.toRadians(arcStart)));

        setTouchInSide(touchInside);
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    }


    @Override
    public boolean onTouchEvent(MotionEvent event) {
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                onStartTrackingTouch();
                updateOnTouch(event);
                break;
            case MotionEvent.ACTION_MOVE:
                updateOnTouch(event);
                break;
            case MotionEvent.ACTION_UP:
                onStopTrackingTouch();
                break;
            case MotionEvent.ACTION_CANCEL:
                onStopTrackingTouch();
                setPressed(false);
                break;
        }
        return true;
    }

    @Override
    protected void drawableStateChanged() {
        super.drawableStateChanged();
        if (getThumb() != null && getThumb().isStateful()) {
            int[] state = getDrawableState();
            getThumb().setState(state);
        }
        invalidate();
    }

    private void onStartTrackingTouch() {
        if (mOnSeekArcChangeListener != null) {
            mOnSeekArcChangeListener.onStartTrackingTouch(this);
        }
    }

    private void onStopTrackingTouch() {
        if (mOnSeekArcChangeListener != null) {
            mOnSeekArcChangeListener.onStopTrackingTouch(this);
        }
    }

    private void updateOnTouch(MotionEvent event) {

        boolean ignoreTouch = ignoreTouch(event.getX(), event.getY());
        if (ignoreTouch) {
            return;
        }

        mTouchAngle = getTouchDegrees(event.getX(), event.getY());
        int progress = getProgressForAngle(mTouchAngle);
        System.out.println(TAG + "mProgress:" + progress);
        onProgressRefresh(progress, true);

    }

    private double getTouchDegrees(float xPos, float yPos) {
        float x = xPos - mTranslateCenterX;
        float y = yPos - mTranslateCenterY;

        double angle = Math.toDegrees(Math.atan2(y, -x) + (Math.PI / 2) - Math.toRadians(rotation));
        if (angle < 0) {
            angle = 360 + angle;
        }
        System.out.println(TAG + "angle:" + angle);
        angle -= getStartAngle();
        return angle;
    }

    private void onProgressRefresh(int progress, boolean fromUser) {
        updateProgress(progress, fromUser);
    }

    private void updateThumbPosition() {
        int thumbAngle = (int) (getStartAngle() + mProgressSweep + rotation + 90);
        mThumbXPos = (int) (arcRadius * Math.cos(Math.toRadians(thumbAngle)));
        mThumbYPos = (int) (arcRadius * Math.sin(Math.toRadians(thumbAngle)));
    }

    private void updateProgress(int progress, boolean fromUser) {

        if (progress == INVALID_PROGRESS_VALUE) {
            return;
        }

        if (mOnSeekArcChangeListener != null) {
            if (getProgress() != progress)
                mOnSeekArcChangeListener.onProgressChanged(this, progress, fromUser);
        }
        //System.out.println(TAG+"mProgress:"+mProgress);

        setProgress(progress);
        mProgressSweep = (float) progress / getMax() * getMaxSweepAngle();

        updateThumbPosition();
        invalidate();
    }

    public void setOnSeekArcChangeListener(OnSeekArcChangeListener l) {
        mOnSeekArcChangeListener = l;
    }

    @Override
    public void setProgress(int progress) {
        super.setProgress(progress);
        updateProgress(progress, false);
    }


    public void setProgressWidth(int progressWidth) {
        super.setProgressWidth(progressWidth);
        mProgressPaint.setStrokeWidth(progressWidth);
    }

    @Override
    public void setArcWidth(int arcWidth) {
        super.setArcWidth(arcWidth);
        arcPaint.setStrokeWidth(arcWidth);
    }

    public int getArcRotation() {
        return rotation;
    }

    public void setArcRotation(int rotation) {
        this.rotation = rotation;
        updateThumbPosition();
    }

    @Override
    public void setStartAngle(int startAngle) {
        super.setStartAngle(startAngle);
        updateThumbPosition();
    }

    @Override
    public void setMaxSweepAngle(int sweepAngle) {
        super.setMaxSweepAngle(sweepAngle);
        updateThumbPosition();
    }

    public void setRoundedEdges(boolean isEnabled) {
        mRoundedEdges = isEnabled;
        if (mRoundedEdges) {
            arcPaint.setStrokeCap(Paint.Cap.ROUND);
            mProgressPaint.setStrokeCap(Paint.Cap.ROUND);
        } else {
            arcPaint.setStrokeCap(Paint.Cap.SQUARE);
            mProgressPaint.setStrokeCap(Paint.Cap.SQUARE);
        }
    }

    public void setTouchInSide(boolean isEnabled) {
        if (getThumb() == null) {
            return;
        }
        int thumbHalfHeight = (int) getThumb().getIntrinsicHeight() / 2;
        int thumbHalfWidth = (int) getThumb().getIntrinsicWidth() / 2;
        touchInside = isEnabled; // true
        if (touchInside) {
            mTouchIgnoreRadius = (float) arcRadius / 4;
        } else {
            //
            mTouchIgnoreRadius = arcRadius - Math.min(thumbHalfWidth, thumbHalfHeight);
        }
    }

    public static double arccos(double a) {
        double b = 90.0, c0 = 0.0, c1 = 180.0;
        if (a < 1 && a > -1) {
            do {
                if (Math.cos(b * Math.PI / 180) >= a) {
                    c0 = b;
                    b = (c0 + c1) / 2;
                }
                if (Math.cos(b * Math.PI / 180) <= a) {
                    c1 = b;
                    b = (c0 + c1) / 2;
                }
            } while (Math.abs(c0 - c1) > 0.00001);
        }
        return b;
    }

    @Override
    protected void onAttachedToWindow() {
        // TODO Auto-generated method stub
        super.onAttachedToWindow();
    }

    private boolean ignoreTouch(float xPos, float yPos) {
        boolean ignore = false;
        float x = xPos - mTranslateCenterX;
        float y = yPos - mTranslateCenterY;

        float touchRadius = (float) Math.sqrt((Math.pow(x, 2) + Math.pow(y, 2)));
        // if (touchRadius < mTouchIgnoreRadius) {
        // ignore = true;
        // }
        if (!(touchRadius > (arcRadius - 80))) {
            ignore = true;
        }
        return ignore;
    }

    @Override
    protected void onDetachedFromWindow() {
        // TODO Auto-generated method stub
        super.onDetachedFromWindow();
    }

    private int getProgressForAngle(double angle) {
        int touchProgress = (int) Math.round(valuePerDegree() * angle);
        System.out.println(TAG + "touchProgress:" + touchProgress);
        touchProgress = (touchProgress < 0) ? INVALID_PROGRESS_VALUE : touchProgress;
        touchProgress = (touchProgress > getMax()) ? getMax() : touchProgress;

        return touchProgress;
    }

    private float valuePerDegree() {
        return (float) getMax() / getMaxSweepAngle();
    }

    public int getProgress() {
        return getProgressForAngle(mTouchAngle);
    }
}